<?php

namespace App\Services\System;

use App\Models\System\MenuGroup as SystemMenuGroup;
use App\Models\System\Menu as SystemMenu;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;

/**
 * 菜单服务类
 * @package App\Services
 */
class Menu
{
    /**
     * 构造函数
     */
    public function __construct()
    {

    }

    /**
     * 获取分组列表
     */
    public function getGroupList()
    {
        $groupList = SystemMenuGroup::all();
        return $groupList;
    }

    /**
     * 获取分组数据
     * @param $groupId
     * @return mixed
     */
    public function getGroupData($groupId)
    {
        return SystemMenuGroup::findOrFail($groupId);
    }

    /**
     * 通过key获取分组数据
     * @param $key
     * @return mixed
     */
    public function getGroupDataByKey($key)
    {
        $data = SystemMenuGroup::where('group_key', $key)->first();
        return $data ? $data->toArray() : [];
    }

    /**
     * 保存数据
     * @param Request $request
     * @return bool
     */
    public function saveGroup($groupData = [])
    {
        if (!empty($groupData['group_id'])) {
            $menuGroup = SystemMenuGroup::find($groupData['group_id']);
        } else {
            $menuGroup = new SystemMenuGroup;
        }
        $menuGroup->group_key = $groupData['group_key'] ?? '';
        $menuGroup->group_name = $groupData['group_name'] ?? '';
        return $menuGroup->save();
    }

    /**
     * 删除模型
     * @param $groupIds
     * @return mixed
     */
    public function delGroup($groupIds)
    {
        $menuGroups = SystemMenuGroup::query()->findMany($groupIds);
        if ($menuGroups->isNotEmpty()) {
            foreach ($menuGroups as $menuGroup) {
                return $menuGroup->delete();
            }
        }
        return true;
    }

    /**
     * 获取菜单列表
     * @param $groupId
     * @return mixed
     */
    public function getMenuList($groupId)
    {
        $menuList = SystemMenu::where('group_id', $groupId)->orderBy('order_num', 'ASC')->orderBy('menu_id', 'ASC')->get()->toArray();
        $newMenuList = [];
        foreach ($menuList as $v) {
            $newMenuList[(int)$v['menu_id']] = $v;
        }
        return $newMenuList;
    }

    /**
     * 回去菜单数据
     * @param $menuId
     * @return mixed
     */
    public function getMenuData($menuId)
    {
        $menuData = SystemMenu::find($menuId);
        return $menuData;
    }

    /**
     * 获取指定菜单下的菜单列表
     * @param $parentId
     * @return mixed
     */
    public function getMenuChildList($parentId)
    {
        $menuList = SystemMenu::where('parent_id', $parentId)->orderBy('order_num', 'ASC')->orderBy('menu_id', 'ASC')->get()->toArray();
        return $menuList;
    }

    /**
     * 通过分组key获取菜单列表
     */
    public function getCacheMenuListByGroupKey($key)
    {
        $cacheKey = 'sys_menu_list_by_group_key:' . $key;
        //Cache::delete($cacheKey);
        $cacheData = Cache::get($cacheKey);
        if (!$cacheData) {
            $groupData = $this->getGroupDataByKey($key);
            if ($groupData) {
                $cacheData = Db::table('sys_menus')
                    ->leftJoin('sys_permissions', 'sys_menus.perm_id', '=', 'sys_permissions.perm_id')
                    ->select('sys_menus.*', 'sys_permissions.name as perm_name', 'sys_permissions.is_public')
                    ->whereNull('sys_menus.deleted_at')
                    ->orderBy('sys_menus.order_num', 'ASC')->orderBy('sys_menus.menu_id', 'ASC')
                    ->get()->map(function ($value) {
                        return (array)$value;
                    })->toArray();
                Cache::put($cacheKey, $cacheData, 60);
            }
        }
        return $cacheData;
    }

    /**
     * 清除用户菜单缓存
     * @param $groupId
     * @return bool
     */
    public function clearMenuListCache($groupId)
    {
        $groupData = $this->getGroupData($groupId);
        if (empty($groupData)) {
            return false;
        }
        $cacheKey = 'sys_menu_list_by_group_key:' . $groupData->group_key;
        return Cache::delete($cacheKey);
    }

    /**
     * 保存菜单数据
     * @param $request
     * @return bool
     */
    public function saveMenu($postData = [])
    {
        if (!empty($postData['menu_id'])) {
            $menuModel = SystemMenu::find($postData['menu_id']);
        } else {
            $menuModel = new SystemMenu();
        }
        $menuModel->group_id = $postData['group_id'] ?? 0;
        $parentId = $postData['parent_id'] ?? 0;
        if ($parentId && $menuModel->menu_id && $parentId == $menuModel->menu_id) {
            throw new \Exception('父级菜单不能为自身');
        }
        $menuModel->parent_id = $parentId;
        $menuModel->menu_key = $postData['menu_key'] ?? '';
        $menuModel->menu_name = $postData['menu_name'] ?? '';
        $menuModel->description = $postData['description'] ?? '';
        $menuModel->perm_id = $postData['perm_id'] ?? 0;
        $menuModel->path = $postData['path'] ?? '';
        $menuModel->component = $postData['component'] ?? '';
        $menuModel->icon = (string)$postData['icon'] ?? '';
        $menuModel->hidden = isset($postData['hidden']) ? (int)$postData['hidden'] : 0;
        $menuModel->hidden_header_content = isset($postData['hidden_header_content']) ? (int)$postData['hidden_header_content'] : 0;
        $menuModel->hide_children = isset($postData['hide_children']) ? (int)$postData['hide_children'] : 0;
        $menuModel->redirect = $postData['redirect'] ?? '';
        $menuModel->target = $postData['target'] ?? '';
        $menuModel->order_num = $postData['order_num'] ?? 0;
        $rs = $menuModel->save();
        //清除缓存
        $this->clearMenuListCache($menuModel->group_id);
        return $rs;
    }

    /**
     * 删除菜单
     * @param array $menuIds
     * @return int
     */
    public function del($menuIds = [])
    {

        $menus = SystemMenu::query()->findMany($menuIds);
        if ($menus->isEmpty()) {
            throw new \Exception('菜单不存在');
        }
        foreach ($menus as $menu) {
            $menu->delete();
        }
        //清除缓存
        $this->clearMenuListCache($menu->first()->group_id);
        return true;
    }

    /**
     * 保存排序数据
     * @param array $draggingNode 拖拽中的节点
     * @param array $dropNode 被放置的节点
     * @param string $dropType 拖拽类型
     * @return bool
     * @throws \Exception
     */
    public function setOrder($draggingNode, $dropNode, $dropType)
    {
        switch ($dropType) {
            case 'before'://拖拽到某个节点之前
            case 'after'://拖拽到某个节点之后
                DB::beginTransaction();
                try {
                    //拖拽节点更改排序数字及父级分类
                    if ($dropType == 'before') {
                        $newOrderNum = $dropNode['order_num'] ?? 0;
                    } else {
                        $newOrderNum = $dropNode['order_num'] ? $dropNode['order_num'] + 1 : 0;
                    }
                    //事先查出菜单列表
                    $sameLevelMenuList = $this->getMenuChildList($dropNode['parent_id']);
                    //拖拽节点更改排序数字及父级分类
                    SystemMenu::query()->find($draggingNode['menu_id'])->update(['parent_id' => $dropNode['parent_id'], 'order_num' => $newOrderNum]);
                    //调整之后节点的排序数字,之后的节点各加2，为插入节点留空隙
                    $isStartSet = false;
                    foreach ($sameLevelMenuList as $menuData) {
                        if ($menuData['menu_id'] == $dropNode['menu_id']) {//从放置节点开始后续排序自动加一
                            $isStartSet = true;
                            if ($dropType == 'after') {//插入到后面，则被放置节点不处理
                                continue;
                            }
                            if ($dropType == 'before') {//插入到前面，从被放置节点开始排序开始调整

                            }
                        }
                        if ($isStartSet && $menuData['menu_id'] != $draggingNode['menu_id']) {
                            $newOrderNum++;
                            SystemMenu::query()->find($menuData['menu_id'])->update(['order_num' => $newOrderNum]);
                        }
                    }
                    DB::commit();
                } catch (\Exception $e) {
                    DB::rollBack();
                    throw new \Exception($e->getMessage());
                }
                break;
            case 'inner'://拖进节点，直接更改父级ID
                SystemMenu::query()->find($draggingNode['menu_id'])->update(['parent_id' => $dropNode['menu_id']]);
                break;
            default:
                throw new \Exception('无效的拖拽类型');
        };
        //清除缓存
        $this->clearMenuListCache($draggingNode['group_id']);
        return true;
    }

    /**
     * 获取菜单所有路由名称列表
     * @param $key
     * @return array|mixed
     */
    public function getMenuRouteList($key)
    {
        $menuList = $this->getCacheMenuListByGroupKey($key);
        $routeList = [];
        if ($menuList) {
            foreach ($menuList as $v) {
                if ($v['perm_name']) {
                    $routeList[] = $v['perm_name'];
                }
            }
        }
        return $routeList;
    }

    /**
     * 获取有权限的菜单列表
     * @param $key
     * @return array|mixed
     */
    public function getHasPermTreeMenuList($key, $userPermList = [])
    {
        $menuList = $this->getCacheMenuListByGroupKey($key);
        if ($menuList) {
            foreach ($menuList as $k => $v) {
                if ($v['perm_name'] && (!in_array($v['perm_name'], $userPermList))) {
                    unset($menuList[$k]);
                }
            }
            $menuList = array_values($menuList);
        }
        return $menuList;
        /*$tree = new \App\Services\Tool\TreeService('menu_id','parent_id', 'children');
        $tree->load($menuList);
        $treelist = $tree->deepTree();
        //过滤无效菜单
        foreach ($treelist as $k => $menu){
            $d1 = data_get($menu, 'children.perm_name');
            if (!empty($d1)){
                $d1 = Arr::where($d1, function ($value, $key) {
                    return !empty($value);
                });
            }
            $d2 = data_get($menu, 'children.*.perm_name');
            if (!empty($d2)){
                $d2 = Arr::where($d2, function ($value, $key) {
                    return !empty($value);
                });
            }
            $d3 = data_get($menu, 'children.*.children.*.perm_name');
            if (!empty($d3)){
                $d3 = Arr::where($d3, function ($value, $key) {
                    return !empty($value);
                });
            }
            if (empty($d1) && empty($d2) && empty($d3)){
                unset($treelist[$k]);
            }
        }
        return array_values($treelist);*/
    }
}
